﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using System.Xml;

namespace Service.Tool
{
    /// <summary>
    /// 日志帮助类
    /// </summary>
    public class LogHelper
    {
        private readonly string Business_path;
        private readonly string CASH_Path;
        private readonly string Device_path;
        private readonly string EXCEPTION_path;
        private readonly string EXCEPTION_UNHANDLED_path;
        private readonly string LOG_BUSINESS = "Business";
        private readonly string LOG_CASH = "CASHLOG";
        private readonly string LOG_Device = "Device";
        private readonly string LOG_EXCEPTION = "Exception";
        private readonly string LOG_EXCEPTION_UNHANDLED = "ExceptionUnHandled";
        private readonly string LOG_MEM = "MEMLOG";
        private readonly string LOG_MSST_ROOT = "Log";
        private readonly string LOG_Proxy = "Proxy";
        private readonly string LOG_TRACE = "Trace";
        private readonly string LOG_Web = "WebParam";
        public int LogLevel;
        private readonly string MEM_path;
        private readonly string PayCallBackData = "PayCallBackData";

        private readonly string Proxy_path;

        //Queue logQueue;
        private readonly string root_path;
        private readonly string TRACE_path;
        private readonly string WebParam_path;


        public LogHelper()
        {
            LogLevel = 0;
            root_path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LOG_MSST_ROOT);
            if (!Directory.Exists(root_path)) Directory.CreateDirectory(root_path);
            EXCEPTION_path = InitLogDirectory(LOG_EXCEPTION);
            EXCEPTION_path = Path.Combine(EXCEPTION_path, GetDailyLogFileName());
            EXCEPTION_UNHANDLED_path = InitLogDirectory(LOG_EXCEPTION_UNHANDLED);
            EXCEPTION_UNHANDLED_path = Path.Combine(EXCEPTION_UNHANDLED_path, GetDailyLogFileName());
            TRACE_path = InitLogDirectory(LOG_TRACE);
            TRACE_path = Path.Combine(TRACE_path, GetDailyLogFileName());
            Device_path = InitLogDirectory(LOG_Device);
            Device_path = Path.Combine(Device_path, GetDailyLogFileName());
            Proxy_path = InitLogDirectory(LOG_Proxy);
            Proxy_path = Path.Combine(Proxy_path, GetDailyLogFileName());
            Business_path = InitLogDirectory(LOG_BUSINESS);
            Business_path = Path.Combine(Business_path, GetDailyLogFileName());
            MEM_path = InitLogDirectory(LOG_MEM);
            MEM_path = Path.Combine(MEM_path, GetDailyLogFileName());
            WebParam_path = InitLogDirectory(LOG_Web);
            WebParam_path = Path.Combine(WebParam_path, GetDailyLogFileName());
            CASH_Path = InitLogDirectory(LOG_CASH);
            CASH_Path = Path.Combine(CASH_Path, GetDailyLogFileName());
            //记录等待上传的支付数据 
            GetPayData_Path = InitNoDateLogDirectory(PayCallBackData);
            GetPayData_Path = Path.Combine(GetPayData_Path, "PayCallBackData.xml");
        }
        //BackgroundWorker bgwLogWriter;

        /// <summary>
        /// 唯一公开值用作给外界调用并且初始化自身的入口点
        /// </summary>
        public static bool Available { get; }


        public string GetPayData_Path { get; }

        public void WriteLogMem(string logMessage)
        {
            //内存日志在等级1或以下记录
            if (LogLevel > 1) return;
            try
            {
                var sb = new StringBuilder();
                sb.Append(DateTime.Now.ToString("[HH:mm:ss.ffff] "));
                sb.Append("[");
                sb.Append(logMessage);
                sb.Append("]");
                sb.Append("\r\n");
                File.AppendAllText(MEM_path, sb.ToString());
            }
            catch
            {
            }
        }

        public void WriteLogWeb(string logMessage)
        {
            //内存日志在等级3或以下记录
            if (LogLevel > 3) return;
            try
            {
                var sb = new StringBuilder();
                sb.Append(DateTime.Now.ToString("[HH:mm:ss.ffff] "));
                sb.Append("[");
                sb.Append(logMessage);
                sb.Append("]");
                sb.Append("\r\n");
                File.AppendAllText(WebParam_path, sb.ToString());
            }
            catch
            {
            }
        }

        public void WriteLogTrace(string logMessage)
        {
            //内存日志在等级4或以下记录
            if (LogLevel > 4) return;
            try
            {
                var sb = new StringBuilder();
                sb.Append(DateTime.Now.ToString("[HH:mm:ss.ffff] "));
                sb.Append("[");
                sb.Append(logMessage);
                sb.Append("]");
                sb.Append("\r\n");
                File.AppendAllText(TRACE_path, sb.ToString());
            }
            catch
            {
            }
        }


        public void WriteLogProxy(string logMessage)
        {
            //内存日志在等级4或以下记录
            if (LogLevel > 4) return;
            try
            {
                var sb = new StringBuilder();
                sb.Append(DateTime.Now.ToString("[HH:mm:ss.ffff] "));
                sb.Append("[");
                sb.Append(logMessage);
                sb.Append("]");
                sb.Append("\r\n");
                File.AppendAllText(Proxy_path, sb.ToString());
            }
            catch
            {
            }
        }

        public void WriteLogException(string logMessage)
        {
            //内存日志在等级5或以下记录
            if (LogLevel > 5) return;
            try
            {
                var sb = new StringBuilder();
                sb.Append(DateTime.Now.ToString("[HH:mm:ss.fffff] "));
                sb.Append("[");
                sb.Append(logMessage);
                sb.Append("]");
                sb.Append("\r\n");
                File.AppendAllText(EXCEPTION_path, sb.ToString());
            }
            catch
            {
            }
        }

        public void WriteLogException(Exception exception)
        {
            //内存日志在等级5或以下记录
            if (LogLevel > 5) return;
            try
            {
                var sb = new StringBuilder();
                sb.Append(DateTime.Now.ToString("[HH:mm:ss.fffff] "));
                sb.Append("[");
                sb.Append(exception.Message);
                sb.Append("]\r\n[");
                sb.Append(exception.StackTrace);
                sb.Append("]");
                sb.Append("\r\n");
                File.AppendAllText(EXCEPTION_path, sb.ToString());
            }
            catch
            {
            }
        }

        public void WriteLogExceptionUnHandled(string logMessage)
        {
            //任何情况都记录
            try
            {
                var sb = new StringBuilder();
                sb.Append(DateTime.Now.ToString("[HH:mm:ss.fffff] "));
                sb.Append("[");
                sb.Append(logMessage);
                sb.Append("]");
                sb.Append("\r\n");
                File.AppendAllText(EXCEPTION_UNHANDLED_path, sb.ToString());
            }
            catch
            {
            }
        }

        public void WriteLogException(int state)
        {
            throw new NotImplementedException();
        }

        public void WriteLogCash(string MsgInfo)
        {
            try
            {
                var sb = new StringBuilder();
                sb.Append(DateTime.Now.ToString("[HH:mm:ss.fffff] "));
                sb.Append("[");
                sb.Append(MsgInfo);
                sb.Append("]");
                sb.Append("\r\n");
                File.AppendAllText(CASH_Path, sb.ToString());
            }
            catch
            {
            }
        }

        public void WriteLogExceptionUnHandled(Exception exception)
        {
            //任何情况都记录
            try
            {
                var sb = new StringBuilder();
                sb.Append(DateTime.Now.ToString("[HH:mm:ss.fffff] "));
                sb.Append("[");
                sb.Append(exception.Message);
                sb.Append("]\r\n[");
                sb.Append(exception.StackTrace);
                sb.Append("]");
                sb.Append("\r\n");
                File.AppendAllText(EXCEPTION_UNHANDLED_path, sb.ToString());
            }
            catch
            {
            }
        }


        public void WriteLogDevice(string logMessage)
        {
            //2级或以下记录硬件日志
            if (LogLevel > 2) return;
            try
            {
                var sb = new StringBuilder();
                sb.Append(DateTime.Now.ToString("[HH:mm:ss.ffff] "));
                sb.Append("[");
                sb.Append(logMessage);
                sb.Append("]");
                sb.Append("\r\n");
                File.AppendAllText(Device_path, sb.ToString());
            }
            catch
            {
            }
        }

        public void WriteLogDevice(byte[] buffer)
        {
            //2级或以下记录硬件日志
            if (LogLevel > 2) return;
            try
            {
                var sb = new StringBuilder();
                sb.Append(DateTime.Now.ToString("[HH:mm:ss.ffff] "));
                sb.Append("[");
                foreach (var item in buffer)
                    sb.Append("0x" + Convert.ToString(item, 16) + ",");
                sb.Remove(sb.Length - 1, 1);
                sb.Append("]");
                sb.Append("\r\n");
                File.AppendAllText(Device_path, sb.ToString());
            }
            catch
            {
            }
        }


        private string InitNoDateLogDirectory(string subFolder)
        {
            var sub_path = Path.Combine(root_path, subFolder);
            if (!Directory.Exists(sub_path)) Directory.CreateDirectory(sub_path);
            return sub_path;
        }

        public string GetFolderName()
        {
            return DateTime.Today.Year.ToString().PadLeft(4, '0') + "-" +
                   DateTime.Today.Month.ToString().PadLeft(2, '0');
        }

        private string GetDailyLogFileName()
        {
            return DateTime.Today.ToString("yyyy-MM-dd") + ".txt";
        }

        private string InitLogDirectory(string subFolder)
        {
            var sub_path = Path.Combine(root_path, subFolder);
            var monthly_path = Path.Combine(sub_path, GetFolderName());
            if (!Directory.Exists(sub_path))
            {
                Directory.CreateDirectory(sub_path);
            }
            else
            {
                //DateTime Tempdate = DateTime.Today.AddMonths(-2);
                //string Monthlast = Tempdate.ToString("yyyy-MM");
                //string MonthNow = DateTime.Now.ToString("yyyy-MM");
                //foreach (var Temp in Directory.GetDirectories(sub_path))
                //{
                //    if (!(Temp.Contains(Monthlast) || Temp.Contains(MonthNow)))
                //    {
                //        try
                //        {
                //            Directory.Delete(Temp, true);
                //        }
                //        catch { }
                //    }
                //}
                var timeArea = -2; //日志保留月数
                var Directories2Reserved = new string[1 - timeArea]; //保留的日志子文件夹名称列表
                var ori = timeArea;
                for (; timeArea <= 0; timeArea++)
                {
                    //根据月份推算需要保留的日志子文件夹名称
                    var Tempdate = DateTime.Today.AddMonths(timeArea);
                    Directories2Reserved[timeArea - ori] = Tempdate.ToString("yyyy-MM");
                }

                var MonthNow = DateTime.Now.ToString("yyyy-MM");
                var directoryInfo = new DirectoryInfo(sub_path).GetDirectories();
                foreach (var Temp in directoryInfo)
                    if (!Directories2Reserved.Contains(Temp.Name))
                        //删除不在保留列表里面的目录
                        try
                        {
                            Directory.Delete(Temp.FullName, true);
                        }
                        catch
                        {
                        }
            }

            if (!Directory.Exists(monthly_path)) Directory.CreateDirectory(monthly_path);
            return monthly_path;
        }

        /// <summary>
        /// 对象序列化成 XML String
        /// </summary>
        private string XmlSerialize<T>(T obj)
        {
            var xmlString = string.Empty;
            var xmlSerializer = new XmlSerializer(typeof(T));
            using (var ms = new MemoryStream())
            {
                xmlSerializer.Serialize(ms, obj);
                xmlString = Encoding.UTF8.GetString(ms.ToArray());
            }

            return xmlString;
        }

        /// <summary>
        /// XML String 反序列化成对象
        /// </summary>
        private T XmlDeserialize<T>(string xmlString)
        {
            var t = default(T);
            var xmlSerializer = new XmlSerializer(typeof(T));
            using (Stream xmlStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlString)))
            {
                using (var xmlReader = XmlReader.Create(xmlStream))
                {
                    var obj = xmlSerializer.Deserialize(xmlReader);
                    t = (T)obj;
                }
            }

            return t;
        }

    }
}
